﻿using CommonEngine;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace CommonDevelop.DB
{
    /// <summary>
    /// 数据层基类(HOF)
    /// (部分业务表达需要按SqlSugar的套路，形成套路外包也是极好)
    /// </summary>
    public abstract class DBBase<T> : IBase<T> where T : BaseEn, new()
    {
        /// <summary>
        /// 针对表默认查询业务的表达式
        /// </summary>
        public virtual Expression<Func<T, bool>> WhereKeyWord(string keyword)
            => null;

        /// <summary>
        /// 针对添加操作，确认匿名映射结构
        /// </summary>
        public virtual Expression<Func<T, object>> AddColumns()
            => null;

        /// <summary>
        /// 通过主键获取单个实例
        /// </summary>
        public virtual T GetEntity(object keyValue)
            => keyValue.IsEmpty() ? default : SugarBizDB.GetReadOnlyOne<T>(keyValue);

        public virtual T GetEntity(Expression<Func<T, bool>> expression, bool IsDelete)
            => this.GetList(expression, IsDelete).FirstOrDefault();

        public virtual IEnumerable<T> GetList(string keyword = null, bool IsDelete = false)
        {
            Expression<Func<T, bool>> whereExp = a => a.IsDelete == IsDelete;
            if (!keyword.IsEmpty())
            {
                var exp = this.WhereKeyWord(keyword);
                if (exp != null)
                    whereExp = whereExp.And(exp);
            }
            return SugarBizDB.GetReadOnlyMore(whereExp);
        }

        public virtual IEnumerable<T> GetList(Expression<Func<T, bool>> expression, bool IsDelete = false)
        {
            Expression<Func<T, bool>> whereExp = a => a.IsDelete == IsDelete;
            if (expression != null)
                whereExp = whereExp.And(expression);

            return SugarBizDB.GetReadOnlyMore(whereExp);
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        public virtual IEnumerable<T> GetPageList(Pagination Pag, Expression<Func<T, bool>> expression, bool IsDelete = false)
        {
            if (Pag == null)
                return Enumerable.Empty<T>();

            var DB = SugarBizDB.GetReadOnlyInstance();
            Expression<Func<T, bool>> whereExp = a => a.IsDelete == IsDelete;
            if (expression != null)
                whereExp = expression;

            var CallExp = Pag.sidx.GetPropertyOrderBy<T>();
            OrderByType OBT = Pag.sord.ToLower() == "asc" ? OrderByType.Asc : OrderByType.Desc;

            int count = 0;
            List<T> data = null;
            if (CallExp != null)
                data = DB.Queryable<T>().Where(whereExp).OrderBy(CallExp, OBT).ToPageList(Pag.page, Pag.rows, ref count);
            else
                data = DB.Queryable<T>().Where(whereExp).ToPageList(Pag.page, Pag.rows, ref count);

            Pag.records = count;
            return data;
        }

        /// <summary>
        /// 关键字分页查询
        /// </summary>
        public virtual IEnumerable<T> GetPageList(Pagination Pag, string keyword = null, bool IsDelete = false)
        {
            if (Pag == null)
                return Enumerable.Empty<T>();

            var DB = SugarBizDB.GetReadOnlyInstance();
            Expression<Func<T, bool>> whereExp = a => a.IsDelete == IsDelete;
            if (!keyword.IsEmpty())
            {
                var exp = this.WhereKeyWord(keyword);
                if (exp != null)
                    whereExp = whereExp.And(exp);
            }

            var CallExp = Pag.sidx.GetPropertyOrderBy<T>();
            OrderByType OBT = Pag.sord.ToLower() == "asc" ? OrderByType.Asc : OrderByType.Desc;

            int count = 0;
            List<T> data = null;
            if (CallExp != null)
                data = DB.Queryable<T>().Where(whereExp).OrderBy(CallExp, OBT).ToPageList(Pag.page, Pag.rows, ref count);
            else
                data = DB.Queryable<T>().Where(whereExp).ToPageList(Pag.page, Pag.rows, ref count);

            Pag.records = count;
            return data;
        }


        public virtual IEnumerable<TVO> GetPull<TVO>(T en)
            where TVO : class, new()
            => Enumerable.Empty<TVO>();

        public virtual IEnumerable<T> GetPush<TVO>(TVO en)
            where TVO : class, new()
            => Enumerable.Empty<T>();


        /// <summary>
        /// 是否有符合条件的数据
        /// </summary>
        public virtual bool IsExist(Expression<Func<T, bool>> predicate)
            => !SugarBizDB.GetReadOnlyOne(predicate).IsNull();

        /// <summary>
        /// 批量插入数据
        /// </summary>
        public virtual int Add_Entities(IEnumerable<T> EnLs, bool Trans)
        {
            if (EnLs.IsNullOrEmpty())
                return 0;
            else
                EnLs.ToList().ForEach(a => a.Modified(DateTime.Now));

            int result = 0;
            var DB = SugarBizDB.GetInstance();
            var exp = this.AddColumns();
            if (exp == null)
            {
                foreach (var v in EnLs)
                    DB.Insertable<T>(v).AddQueue();
                //将n条插入一起执行带有事务，如果外部有事务会走外部事务，外部没事务会走内部事务
                result = DB.SaveQueues();
            }
            else
            {
                if (Trans)
                {
                    try
                    {
                        DB.BeginTran();
                        //插入多条数据
                        result = DB.Insertable<T>(EnLs).InsertColumns(exp).ExecuteCommand();
                        //提交事务
                        DB.CommitTran();
                    }
                    catch (Exception e)
                    {
                        DB.RollbackTran();  //回滚事务
                        throw e;
                    }
                }
                else
                    result = DB.Insertable<T>(EnLs).InsertColumns(exp).ExecuteCommand();
            }
            return result;
        }
        /// <summary>
        /// 批量更新数据
        /// </summary>
        public virtual int Update_Entities(IEnumerable<T> EnLs, bool Trans, Expression<Func<T, object>> Columns = null)
        {
            if (EnLs.IsNullOrEmpty())
                return 0;
            else
                EnLs.ToList().ForEach(a => a.Modified(DateTime.Now));

            int result = 0;
            var DB = SugarBizDB.GetInstance();
            if (Trans)
            {
                try
                {
                    DB.BeginTran();
                    if (Columns == null)
                        result = DB.Updateable<T>(EnLs).ExecuteCommand();
                    else
                        result = DB.Updateable<T>(EnLs).UpdateColumns(Columns).ExecuteCommand();
                    //提交事务
                    DB.CommitTran();
                }
                catch (Exception ex)
                {
                    DB.RollbackTran();  //回滚事务
                    throw ex;
                }
            }
            else
            {
                if (Columns == null)
                    result = DB.Updateable<T>(EnLs).ExecuteCommand();
                else
                {
                    try
                    {
                        result = DB.Updateable<T>(EnLs).UpdateColumns(Columns).ExecuteCommand();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 添加单条数据
        /// </summary>
        public virtual bool Add_Entity(T En, bool Trans)
        {
            if (En == null)
                return false;
            else
                En.Modified(DateTime.Now);

            var exp = this.AddColumns();
            var DB = SugarBizDB.GetInstance();
            if (Trans)
            {
                try
                {
                    DB.BeginTran();
                    if (exp == null)
                        DB.Insertable<T>(En).IgnoreColumns(true).ExecuteCommand();
                    else
                        DB.Insertable<T>(En).InsertColumns(exp).ExecuteCommand();

                    DB.CommitTran();
                }
                catch (Exception e)
                {
                    DB.RollbackTran();
                    throw e;
                }
            }
            else
            {
                if (exp == null)
                    DB.Insertable<T>(En).IgnoreColumns(true).ExecuteCommand();
                else
                    DB.Insertable<T>(En).InsertColumns(exp).ExecuteCommand();
            }
            return true;
        }
        /// <summary>
        /// 保存更新数据
        /// </summary>
        public virtual bool Update_Entity(T En, bool Trans)
        {
            if (En == null)
                return false;
            else
                En.Modified(DateTime.Now);

            var DB = SugarBizDB.GetInstance();
            if (Trans)
            {
                try
                {
                    DB.BeginTran();
                    DB.Updateable<T>(En).ExecuteCommand();
                    DB.CommitTran();
                }
                catch (Exception e)
                {
                    DB.RollbackTran();
                    throw e;
                }
            }
            else
                DB.Updateable<T>(En).ExecuteCommand();

            return true;
        }
        /// <summary>
        /// 更新数据（可忽略字段）
        /// </summary>
        public virtual bool Update_EntityIgnore(T En, Expression<Func<T, object>> IgnoreColumns)
        {
            if (En == null)
                return false;
            else
                En.Modified(DateTime.Now);

            var DB = SugarBizDB.GetInstance();
            try
            {
                DB.BeginTran();
                DB.Updateable<T>(En).IgnoreColumns(IgnoreColumns).ExecuteCommand();
                DB.CommitTran();
            }
            catch (Exception e)
            {
                DB.RollbackTran();
                throw e;
            }
            return true;
        }
        /// <summary>
        /// 更新数据（可指定字段）
        /// </summary>
        public virtual bool Update_EntityColumns(T En, Expression<Func<T, object>> columns)
        {
            if (En == null)
                return false;
            else
                En.Modified(DateTime.Now);

            var DB = SugarBizDB.GetInstance();
            try
            {
                DB.BeginTran();
                DB.Updateable<T>(En).UpdateColumns(columns).ExecuteCommand();
                DB.CommitTran();
            }
            catch (Exception e)
            {
                DB.RollbackTran();
                throw e;
            }
            return true;
        }
        /// <summary>
        /// 批量更新数据（指定条件）
        /// </summary>
        public virtual bool Update_Batch(Expression<Func<T, T>> columns, Expression<Func<T, bool>> expression)
        {
            if (columns == null || expression == null)
                return false;

            var DB = SugarBizDB.GetInstance();
            try
            {
                DB.BeginTran();
                DB.Updateable<T>(columns).Where(expression).ExecuteCommand();
                DB.CommitTran();
            }
            catch (Exception e)
            {
                DB.RollbackTran();
                throw e;
            }
            return true;
        }

        /// <summary>
        /// 删除数据(long)
        /// </summary>
        public virtual bool Delete(params long[] keyValue)
            => SugarBizDB.Delete<T>(keyValue);

        /// <summary>
        /// 删除数据(guid)
        /// </summary>
        public virtual bool Delete(params string[] keyValue)
            => SugarBizDB.Delete<T>(keyValue);

        /// <summary>
        /// 删除数据(按条件)
        /// </summary>
        public virtual bool Delete_Batch(Expression<Func<T, bool>> expression)
             => SugarBizDB.Delete_Batch<T>(expression);

        /// <summary>
        /// 删除数据(实例)
        /// </summary>
        public virtual bool Delete_Entity(T En)
        {
            if (En == null)
                return false;

            var DB = SugarBizDB.GetInstance();
            long Id = 0;
            string No = null;
            var t = SugarBizDB.Get_PrimaryKeyValue(En, out Id, out No);
            try
            {
                DB.BeginTran();
                if (t == null)
                    DB.Deleteable<T>().Where(En).ExecuteCommand();
                else
                {
                    if (t == typeof(long) && Id > 0)
                        DB.Deleteable<T>().In(Id).ExecuteCommand();
                    else if (t == typeof(string) && !No.IsEmpty())
                        DB.Deleteable<T>().In(No).ExecuteCommand();
                    else
                    {
                        DB.RollbackTran();
                        return false;
                    }
                }
                DB.CommitTran();
            }
            catch (Exception e)
            {
                DB.RollbackTran();
                throw e;
            }
            return true;
        }
    }
}
